#include <iostream>
#include <string>
#include <math.h>
#include <fstream>
#include <algorithm>
#include <stdio.h>
#include <boost/filesystem/path.hpp>
#include <boost/program_options.hpp>
#include "get_arg.h"



// link with -lboost_filesystem-gcc -lboost_program_options-gcc
// program_options_helper.cpp
//-lboost_filesystem-gcc-d
//-L/usr/local/lib





// my functions
#include <seq_pairs.h>
#include <print_error.h>
#include <program_options_helper.h>
#include <stlhelper.h>
#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <blast_results.h>
#include <codeml_results.h>

using std::string;
using std::cerr;
using std::string;
using std::ofstream;
using std::ifstream;
using std::cerr;
using std::cout;
using std::max;
using boost::filesystem::path;
#define DEFAULT_CODEML_PATH "/net/cpp-group/tools/paml/"
using namespace program_options_helper;
namespace po = boost::program_options_lg;


//_______________________________________________________________________________________

//		process_command_line_options

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________
bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{

	//
	// checked mandatory arguments
	//
	po::options_description mandatory_args("Mandatory Arguments");
	mandatory_args.add_options()
	("cdna_sequences,c", 		po::value<string>(&args.file_cdna)->set_name("FILE"),
								  "FILE with cDNA in FASTA format.\n"
								  "Sequences need not be in order.");



	args.optional_args.add_options()
	("aligned,a",				po::bool_switch(&args.aligned),
									"cDNA sequences are already aligned.")
	("allvsall,A",				po::bool_switch(&args.all_vs_all),
									"All vs. all comparisons. Requires --aligned")
	("regex,r", 				po::value<string>(&args.regex)->set_name("REGEX")
										->default_value("(\\S+)"),
									"Regular expression for extracting the sequence identifier. "
									"Defaults to first non-whitespace accession characters.")
	("paml_exe_path,P", 		po::value<string>(&args.paml)->set_name("PATH"),
									"path to codeml or yn00. Defaults to \1"
									DEFAULT_CODEML_PATH "codeml or \1"
									DEFAULT_CODEML_PATH "yn00.")
	("temp_directory,t",		po::value<string>(&args.tempdir)->set_name("PATH")
										->default_value("tmp"),
									"Working directory for paml.")
	("keep_temp_directory,k",   po::bool_switch(&args.keep_tempdir),
									"Do not remove temporary files PAML created after "
									"programme exit.")
	("yn00,y",			    	po::bool_switch(&args.yn00),
									"Use yn00 rather than codeml.")
	("Free_codon_frequency,F",	po::bool_switch(&args.f61),
									"Sets the codeml codon frequency model to F61 (use "
									"actual codons frequencies) rather than F3x4 "
									"(estimate from nucleotide frequencies at the three "
									"positions).\n"
									"Only makes sense if --yn00 is not specified")
	("header,H",		    	po::bool_switch(&args.results_header),
									"Add a column header line to the results.")
	("columns,C",					"Print list of columns headers (and exit).")
	("paml_err_log,p", 			po::value<string>(&args.kaks_error_log_name)->set_name("PATH"),
									"File for logging codeml or yn00 failures.")
	("#comment,#",				po::value<string>(&args.comment_letters)
										->set_name("LETTERS")
										->default_value("#"),
									"Use one of these letters to begin a "
									"commented line. Comment lines are discarded.");

	args.add_std_options();
	po::options_description all_args("");
	all_args.add(mandatory_args).add(args.optional_args);

	// parse command line
	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv).options(all_args).run(), vm);
	po::notify(vm);

	if (vm.count("version"))
	{
		print_version(cerr, *argv, "1.6\n"
			"\tHistory: \n\n"
			"\tv 1.1\1"
			"11-01-2005\1"
			"Now removes and reports stop codons automatically.\1"
			"--allvsall added.\1"
			"Detects when codeml fails to calculate variances.\1"
			"Saves codeml error messages from both STDOUT and STDIN.\1"
			"--kaks_err_log option changed to --paml_err_log.\1"
			"\tv 1.2\1"
			"13-01-2005\1"
			"Fixed bug where gaps in get_gaps_from_prot_sequence() were not "
				"cleared, leading to exponential growth in memory consumption.\n"
			"\tv 1.3\1"
			"04-02-2005\1"
			"Removes temp directory unless directed to keep it.\1"
				"(--keep_temp_directory)\1Two levels of verbose.\n"
			"\tv 1.4\1"
			"12-08-2005\1"
			"Time out hung kaks jobs\n"
			"\tv 1.5\1"
			"04-01-2006\1"
			"For Andreas: Hash start comment lines. Fix bugs in handling input. Upgrade to common code "
			"for sequence pair identifiers\n"
			"\tv 1.6\1"
			"27-03-2006\1"
			"Comments can begin with user-defined letters. Defaults to hash '#'\n"
			"\tv 1.7\1"
			"18-10-2006\1"
			"Added --Free_codon_frequency parameter to set codon frequency model for codeml."
			"Fixed bug where F1/61 was specified previously."
			"\tv 1.8\1"
			"19-12-2006\1"
			"Bug fix for Caleb.\1"
			"Sequence identifiers do not have to be unique for pairwise aligned "
			"comparisons.\n"
					  
			);
		return false;
	}
	if (vm.count("help"))
	{
		string exe_description =
					"Calculates KaKs for specified sequence pairs.\n"
					"Alignment data from seq_pairs_align should be supplied via STDIN.\n"
					"Otherwise, specify --aligned for aligned cDNA sequences. "
					"Pairwise comparisons are the default. Multiple alignments "
					"can be analysed by adding --allvsall as well.\n"
					"The column names for the resulting output can be "
					"obtained using --columns.\n"
					"N.B. Two levels of verbose (specify --verbose twice for "
					"exhaustive details)\n";

		print_usage(cerr, string(*argv), "--cdna_sequences FILE\n[OPTIONS]\n"
											"[< ALIGNMENT_DATA] > KAKS.RESULTS",
							all_args, exe_description, 80);
		return false;
	}
	if (vm.count("columns"))
	{
		cout	<< seq_pairs		::column_names() << "\t"
				<< t_codeml_results	::column_names() << "\t"
				<< bcpp_align::t_align_results	::column_names() << "\n";
		return false;

	}
	check_required_options(vm, mandatory_args);

	if (args.all_vs_all && !args.aligned)
	{
		throw std::runtime_error("The --allvsall option can only be specified for "
									"multiply aligned cDNA.\n"
									"Please specify the --aligned option as well.");
	}
	if (!args.paml.length())
	{
		if (args.yn00)
			args.paml= DEFAULT_CODEML_PATH "yn00";
		else
			args.paml= DEFAULT_CODEML_PATH "codeml";
	}
	args.open_log_files();

	args.open_err_log();
	return true;
}




void t_program_args::open_log_files()
{
	// make sure the error log file is valid


	if (kaks_error_log_name.length())
	{
		f_kaks_err_log.open(kaks_error_log_name.c_str(), std::ios_base::out | std::ios_base::ate);
		if (!f_kaks_err_log.good())
			throw std::runtime_error("Could not open the error log file (" +
										kaks_error_log_name + ")");
		kaks_log_to_file = true;
	}
}












